#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "TcpServer.h"
#include "TcpConnection.h"
#include "Log.h"

int TcpServer::acceptConnection()
{
    // 和客户端建立连接
    printf("acceptConnection\n");
    int32_t cfd = accept(m_lfd, nullptr, nullptr);
    printf("主线程 新连接cfd = %d\n", cfd);
    // 从线程池中取出一个子线程的反应堆实例，去处理这个cfd
    EventLoop *evLoop = m_threadPool->takeWorkerEventLoop(); // 如果没有子线程 则返回主线程的mainEventLoop
    // 将cfd放到TcpConnetction中处理
    TcpConnection *conn = new TcpConnection(cfd, evLoop);
    return 0;
}

void TcpServer::run()
{
    // 启动线程池
    m_threadPool->run();
    // 添加检测的任务
    auto acceptConnectionObj = [this](void *arg) {return acceptConnection();};
    Channel *channel = new Channel(m_lfd, FDEvent::ReadEvent, acceptConnectionObj, nullptr, nullptr, nullptr);
    m_mainLoop->addTask(channel, ElemType::ADD);
    // 启动反应堆模型
    printf("添加监听 lfd\n");
    m_mainLoop->run();
}

TcpServer::TcpServer(uint16_t port, int32_t threadNum)
{
    m_port = port;
    m_threadNum = threadNum;
    m_mainLoop = new EventLoop(EventLoopModelType::POLL);
    m_threadPool = new ThreadPool(m_mainLoop, threadNum);
    setListen();
}

TcpServer::~TcpServer()
{
}

void TcpServer::setListen()
{
    // 1.创建监听的fd
    m_lfd = socket(AF_INET, SOCK_STREAM, 0);
    if (m_lfd == -1)
    {
        perror("socket");
        return;
    }
    // 2.设置端口复用
    uint32_t opt = 1;
    int32_t ret = setsockopt(m_lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if (ret == -1)
    {
        perror("setsockopt");
        return;
    }
    // 3.绑定IP和端口
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(m_port);
    addr.sin_addr.s_addr = INADDR_ANY;
    ret = bind(m_lfd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret == -1)
    {
        perror("bind");
        return;
    }
    // 4.设置监听
    ret = listen(m_lfd, 128);
    if (ret == -1)
    {
        perror("listen");
        return;
    }
    printf("主线程监听成功 lf = %d\n", m_lfd);
}
